#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Fluent UI版本的机器人舞蹈控制系统
使用PyQt-Fluent-Widgets构建现代化界面
"""

import sys
import os
import json
import requests
import numpy as np
import random
import time
from PyQt5.QtCore import Qt, QTimer, QSize, Q_ARG, QMetaObject, pyqtSlot
from PyQt5.QtGui import QFont, QPixmap, QIcon
from PyQt5.QtWidgets import (QApplication, QFileDialog, QMessageBox, QWidget, 
                           QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QTextEdit,
                           QPushButton, QComboBox, QSpinBox, QDoubleSpinBox, 
                           QProgressBar, QGroupBox, QTabWidget, QStyle, QDialog,
                           QListWidget, QListWidgetItem, QSlider)

# QFluentWidgets imports
try:
    from qfluentwidgets import (FluentWindow, PrimaryPushButton, PushButton, ToggleButton,
                              ComboBox, LineEdit, TextEdit, ProgressBar, CardWidget,
                              InfoBar, InfoBarPosition, Theme, setTheme, setThemeColor)
except ImportError as e:
    print("导入QFluentWidgets库时出错:")
    print(str(e))
    print("请确保已正确安装QFluentWidgets库:")
    print("pip install PyQt-Fluent-Widgets")
    sys.exit(1)

import threading
from main_controller import get_main_controller
from system_state import SystemState
from motion_generator import DanceMode

# 添加语音识别相关导入
try:
    from xfyun_speech import recognize_speech
    SPEECH_RECOGNITION_AVAILABLE = True
except ImportError:
    SPEECH_RECOGNITION_AVAILABLE = False
    print("未找到xfyun_speech模块，语音识别功能不可用")

try:
    import serial
    import serial.tools.list_ports
    SERIAL_AVAILABLE = True
except ImportError:
    SERIAL_AVAILABLE = False
    print("未找到pyserial库，串口功能不可用")


class FluentMainUI(FluentWindow):
    """
    基于QFluentWidgets的主界面类
    实现现代化Fluent Design风格的用户交互界面
    """
    
    def __init__(self):
        """初始化主界面"""
        super().__init__()
        self.controller = get_main_controller()
        
        # 界面状态
        self.updating = False
        
        # 预设动作库编辑状态标志位
        self.is_preset_editing = False
        
        # 设置主题颜色
        setThemeColor('#3daee9')
        
        self.waveform_display = None
        self.timeline_editor = None
        self.waveform_data = None
        self.waveform_time = None
        
        # 初始化音乐播放器
        self.init_music_player()
        
        # 初始化界面
        self.init_ui()
        
        # 在界面创建完成后更新波形显示
        self.update_waveform_display()
        
    def init_ui(self):
        """初始化用户界面"""
        self.setWindowTitle('机器人舞蹈控制系统')
        self.resize(1024, 768)
        
        # 创建并添加各个标签页
        self.music_interface = self.create_music_interface()
        self.music_interface.setObjectName("musicInterface")
        self.dance_interface = self.create_dance_interface()
        self.dance_interface.setObjectName("danceInterface")
        self.sequence_interface = self.create_sequence_interface()
        self.sequence_interface.setObjectName("sequenceInterface")
        self.ai_interface = self.create_ai_interface()  # 新增AI对话界面
        self.ai_interface.setObjectName("aiInterface")
        self.monitor_interface = self.create_monitor_interface()
        self.monitor_interface.setObjectName("monitorInterface")
        self.settings_interface = self.create_settings_interface()
        self.settings_interface.setObjectName("settingsInterface")
        
        # 添加导航项
        self.addSubInterface(self.music_interface, QIcon(), "🎵 音乐控制")
        self.addSubInterface(self.dance_interface, QIcon(), "💃 舞蹈展示")
        self.addSubInterface(self.sequence_interface, QIcon(), "📝 序列编辑")
        self.addSubInterface(self.ai_interface, QIcon(), "🤖 AI对话")
        self.addSubInterface(self.monitor_interface, QIcon(), "📊 实时监控")
        self.addSubInterface(self.settings_interface, QIcon(), "⚙️ 参数设置")
        
        # 设置默认界面
        self.switchTo(self.music_interface)
        
        # 初始化定时器
        self.init_timers()
        
        # 恢复自动初始化系统
        self.initialize_system()
        
    def init_audio_player(self):
        """初始化音频播放器组件"""
        try:
            from audio_player import AudioPlayer
            self.audio_player = AudioPlayer()
            print("音频播放器初始化成功")
        except ImportError as e:
            print(f"无法导入音频播放器模块: {e}")
            self.audio_player = None
        except Exception as e:
            print(f"初始化音频播放器时出错: {e}")
            self.audio_player = None
            
    def init_music_player(self):
        """初始化音乐播放器"""
        try:
            import pygame
            pygame.mixer.init()
            self.pygame = pygame
            self.music_loaded = False
            print("音乐播放器初始化成功")
        except ImportError:
            print("警告: 无法导入pygame，音乐播放功能将不可用")
            self.pygame = None
            self.music_loaded = False
        except Exception as e:
            print(f"音乐播放器初始化失败: {e}")
            self.pygame = None
            self.music_loaded = False
            
    def browse_music_file(self):
        """浏览音乐文件"""
        filename, _ = QFileDialog.getOpenFileName(
            self, "选择音乐文件", "", "音频文件 (*.wav *.mp3 *.flac)")
        if filename:
            self.music_file_edit.setText(filename)
            
    def create_music_interface(self):
        """创建音乐控制界面"""
        interface = QWidget()
        layout = QVBoxLayout(interface)
        layout.setSpacing(15)
        
        # 音频文件选择区域
        audio_group = CardWidget()
        audio_layout = QVBoxLayout(audio_group)
        audio_layout.setContentsMargins(20, 20, 20, 20)
        
        file_select_layout = QHBoxLayout()
        self.music_file_edit = LineEdit()
        self.music_file_edit.setPlaceholderText("请选择或拖入音频文件")
        self.browse_music_btn = PushButton("浏览")
        self.browse_music_btn.clicked.connect(self.browse_music_file)
        file_select_layout.addWidget(self.music_file_edit)
        file_select_layout.addWidget(self.browse_music_btn)
        
        audio_layout.addLayout(file_select_layout)
        
        # 控制按钮区域
        control_layout = QHBoxLayout()
        self.play_btn = PrimaryPushButton("播放")
        self.pause_btn = PushButton("暂停")
        self.stop_btn = PushButton("停止")
        self.play_btn.clicked.connect(self.play_music)
        self.pause_btn.clicked.connect(self.pause_music)
        self.stop_btn.clicked.connect(self.stop_music)
        self.pause_btn.setEnabled(False)
        self.stop_btn.setEnabled(False)
        control_layout.addWidget(self.play_btn)
        control_layout.addWidget(self.pause_btn)
        control_layout.addWidget(self.stop_btn)
        audio_layout.addLayout(control_layout)
        
        # 音量控制区域
        volume_group = CardWidget()
        volume_layout = QVBoxLayout(volume_group)
        volume_layout.setContentsMargins(20, 20, 20, 20)
        
        volume_title = QLabel("音量控制")
        volume_title.setFont(QFont("Arial", 12, QFont.Bold))
        volume_layout.addWidget(volume_title)
        
        volume_control_layout = QHBoxLayout()
        self.volume_slider = QSlider(Qt.Horizontal)
        self.volume_slider.setRange(0, 100)
        self.volume_slider.setValue(50)
        self.volume_slider.valueChanged.connect(self.on_volume_changed)
        self.volume_label = QLabel("50%")
        self.volume_label.setMinimumWidth(40)
        self.volume_label.setAlignment(Qt.AlignCenter)
        volume_control_layout.addWidget(QLabel("音量:"))
        volume_control_layout.addWidget(self.volume_slider)
        volume_control_layout.addWidget(self.volume_label)
        volume_layout.addLayout(volume_control_layout)
        
        # 添加到主布局
        layout.addWidget(audio_group)
        layout.addWidget(volume_group)
        layout.addStretch(1)
        
        return interface

    def on_volume_changed(self, value):
        """音量变化处理函数"""
        # 更新音量显示标签
        self.volume_label.setText(f"{value}%")
        
        # 如果使用pygame播放音乐，则设置音乐音量
        try:
            # 注意：pygame的音量范围是0.0到1.0
            if self.pygame and self.music_loaded:
                volume = value / 100.0
                self.pygame.mixer.music.set_volume(volume)
        except Exception as e:
            print(f"设置音量时出错: {e}")
            
    def update_waveform_display(self, data=None):
        """更新波形显示"""
        pass
        
    def create_dance_interface(self):
        """创建舞蹈展示界面"""
        interface = QWidget()
        layout = QVBoxLayout(interface)
        layout.setSpacing(15)
        
        # 机器人连接区域
        connection_group = CardWidget()
        connection_layout = QVBoxLayout(connection_group)
        connection_layout.setContentsMargins(20, 20, 20, 20)
        
        connection_title = QLabel("机器人连接")
        connection_title.setFont(QFont("Arial", 12, QFont.Bold))
        connection_layout.addWidget(connection_title)
        
        # 连接设置
        connect_setting_layout = QHBoxLayout()
        self.robot_address_edit = LineEdit()
        self.robot_address_edit.setPlaceholderText("请输入机器人地址 (IP:端口)")
        self.robot_address_edit.setText("192.168.1.17:8080")
        self.connect_btn = PrimaryPushButton("连接")
        self.disconnect_btn = PushButton("断开")
        self.disconnect_btn.setEnabled(False)
        self.connect_btn.clicked.connect(self.connect_robot)
        self.disconnect_btn.clicked.connect(self.disconnect_robot)
        connect_setting_layout.addWidget(QLabel("地址:"))
        connect_setting_layout.addWidget(self.robot_address_edit)
        connect_setting_layout.addWidget(self.connect_btn)
        connect_setting_layout.addWidget(self.disconnect_btn)
        connection_layout.addLayout(connect_setting_layout)
        
        # 连接状态显示
        self.connection_status_label = QLabel("连接状态: 未连接")
        connection_layout.addWidget(self.connection_status_label)
        
        # 舞蹈模式选择
        mode_group = CardWidget()
        mode_layout = QVBoxLayout(mode_group)
        mode_layout.setContentsMargins(20, 20, 20, 20)
        
        mode_label = QLabel("舞蹈模式")
        mode_label.setFont(QFont("Arial", 12, QFont.Bold))
        self.mode_combo = ComboBox()
        self.mode_combo.addItems(["实时跟随", "预设动作", "即兴创作", "编辑模式"])
        self.mode_combo.setCurrentIndex(0)
        
        mode_layout.addWidget(mode_label)
        mode_layout.addWidget(self.mode_combo)
        
        # 机器人模型显示区域
        model_group = CardWidget()
        model_layout = QVBoxLayout(model_group)
        model_layout.setContentsMargins(20, 20, 20, 20)
        
        # 创建机器人图片显示控件
        self.robot_image_label = QLabel()
        self.robot_image_label.setAlignment(Qt.AlignCenter)
        self.robot_image_label.setMinimumHeight(300)
        self.robot_image_label.setStyleSheet("""
            QLabel {
                background-color: #f0f0f0;
                border: 1px solid #3daee9;
                border-radius: 8px;
            }
        """)
        
        # 初始化显示默认机器人图片
        self.show_robot_image("robot_default.png")
        
        model_layout.addWidget(QLabel("机器人模型"))
        model_layout.addWidget(self.robot_image_label)
        
        # 舞蹈控制按钮
        control_group = CardWidget()
        control_layout = QHBoxLayout(control_group)
        control_layout.setContentsMargins(20, 20, 20, 20)
        self.start_dance_btn = PrimaryPushButton("开始舞蹈")
        self.stop_dance_btn = PushButton("停止舞蹈")
        self.start_dance_btn.setEnabled(False)  # 默认禁用，连接后启用
        self.stop_dance_btn.setEnabled(False)
        self.start_dance_btn.clicked.connect(self.start_dance)
        self.stop_dance_btn.clicked.connect(self.stop_dance)
        control_layout.addWidget(self.start_dance_btn)
        control_layout.addWidget(self.stop_dance_btn)
        
        # 添加到主布局
        layout.addWidget(connection_group)
        layout.addWidget(mode_group)
        layout.addWidget(model_group)
        layout.addWidget(control_group)
        layout.addStretch(1)
        
        return interface
        
    def show_robot_image(self, image_filename):
        """显示机器人图片"""
        try:
            image_path = os.path.join("robot_images", image_filename)
            if os.path.exists(image_path):
                pixmap = QPixmap(image_path)
                # 缩放图片以适应显示区域，保持宽高比
                scaled_pixmap = pixmap.scaled(
                    self.robot_image_label.size(),
                    Qt.KeepAspectRatio,
                    Qt.SmoothTransformation
                )
                self.robot_image_label.setPixmap(scaled_pixmap)
            else:
                # 如果指定的图片不存在，显示默认图片
                default_path = os.path.join("robot_images", "robot_default.png")
                if os.path.exists(default_path):
                    pixmap = QPixmap(default_path)
                    scaled_pixmap = pixmap.scaled(
                        self.robot_image_label.size(),
                        Qt.KeepAspectRatio,
                        Qt.SmoothTransformation
                    )
                    self.robot_image_label.setPixmap(scaled_pixmap)
                else:
                    # 如果默认图片也不存在，显示文字提示
                    self.robot_image_label.setText("机器人图片显示区域")
        except Exception as e:
            print(f"显示机器人图片时出错: {e}")
            self.robot_image_label.setText("图片加载失败")
            
    def resizeEvent(self, event):
        """处理窗口大小调整事件"""
        # 当窗口大小调整时，重新缩放机器人图片
        if hasattr(self, 'robot_image_label'):
            # 获取当前显示的图片并重新缩放
            pixmap = self.robot_image_label.pixmap()
            if pixmap and not pixmap.isNull():
                scaled_pixmap = pixmap.scaled(
                    self.robot_image_label.size(),
                    Qt.KeepAspectRatio,
                    Qt.SmoothTransformation
                )
                self.robot_image_label.setPixmap(scaled_pixmap)
        super().resizeEvent(event)
        
    def create_sequence_interface(self):
        """创建序列编辑界面"""
        interface = QWidget()
        layout = QVBoxLayout(interface)
        layout.setSpacing(15)
        
        # 时间轴编辑区域
        timeline_group = CardWidget()
        timeline_layout = QVBoxLayout(timeline_group)
        timeline_layout.setContentsMargins(20, 20, 20, 20)
        
        # 导入时间轴编辑器组件
        try:
            from timeline_editor import TimelineEditorWidget
            self.timeline_editor = TimelineEditorWidget()
            timeline_layout.addWidget(QLabel("时间轴编辑器"))
            timeline_layout.addWidget(self.timeline_editor)
        except ImportError:
            self.timeline_editor = QTextEdit()
            self.timeline_editor.setPlaceholderText("时间轴序列编辑区域\n格式: 时间(秒) -> 动作代码")
            timeline_layout.addWidget(QLabel("时间轴编辑器"))
            timeline_layout.addWidget(self.timeline_editor)
        
        # 预设动作库
        preset_group = CardWidget()
        preset_layout = QVBoxLayout(preset_group)
        preset_layout.setContentsMargins(20, 20, 20, 20)
        
        # 预设动作库标题和按钮
        preset_header_layout = QHBoxLayout()
        preset_header_layout.addWidget(QLabel("预设动作"))
        self.edit_preset_btn = PushButton("编辑")
        self.save_preset_btn = PushButton("保存库")
        self.load_preset_btn = PushButton("加载库")
        self.edit_preset_btn.clicked.connect(self.edit_preset_library)
        self.save_preset_btn.clicked.connect(self.save_preset_library)
        self.load_preset_btn.clicked.connect(self.load_preset_library)
        preset_header_layout.addWidget(self.edit_preset_btn)
        preset_header_layout.addWidget(self.save_preset_btn)
        preset_header_layout.addWidget(self.load_preset_btn)
        preset_layout.addLayout(preset_header_layout)
        
        self.preset_list = QTextEdit()
        self.preset_list.setPlaceholderText("预设动作库\n点击动作可添加到时间轴")
        self.preset_list.mousePressEvent = self.preset_list_clicked  # 添加点击事件处理
        self.preset_list.setReadOnly(True)  # 设置为只读，避免用户误编辑
        preset_layout.addWidget(self.preset_list)
        
        # 初始化预设动作库
        self.init_preset_actions()
        
        # 控制按钮
        control_layout = QHBoxLayout()
        self.add_action_btn = PushButton("添加自定义动作")
        self.save_sequence_btn = PrimaryPushButton("保存序列")
        self.load_sequence_btn = PushButton("加载序列")
        self.clear_sequence_btn = PushButton("清空序列")
        self.add_action_btn.clicked.connect(self.add_custom_action)
        self.save_sequence_btn.clicked.connect(self.save_sequence)
        self.load_sequence_btn.clicked.connect(self.load_sequence)
        self.clear_sequence_btn.clicked.connect(self.clear_sequence)
        control_layout.addWidget(self.add_action_btn)
        control_layout.addWidget(self.save_sequence_btn)
        control_layout.addWidget(self.load_sequence_btn)
        control_layout.addWidget(self.clear_sequence_btn)
        
        # 添加到主布局
        layout.addWidget(timeline_group)
        layout.addWidget(preset_group)
        layout.addLayout(control_layout)
        layout.addStretch(1)
        
        return interface
        
    def init_preset_actions(self):
        """初始化预设动作库"""
        # 定义预设动作数据
        preset_actions = [
            {
                "name": "挥手打招呼",
                "joint_angles": {
                    "left_arm": -45,
                    "right_arm": -45,
                    "head": 0,
                    "left_leg": 0,
                    "right_leg": 0
                },
                "duration": 1.0,
                "description": "双臂抬起挥手"
            },
            {
                "name": "点头致意",
                "joint_angles": {
                    "head": 30,
                    "left_arm": 0,
                    "right_arm": 0,
                    "left_leg": 0,
                    "right_leg": 0
                },
                "duration": 0.5,
                "description": "头部点头动作"
            },
            {
                "name": "左右摇摆",
                "joint_angles": {
                    "head": -30,
                    "left_arm": 30,
                    "right_arm": -30,
                    "left_leg": 0,
                    "right_leg": 0
                },
                "duration": 1.0,
                "description": "头部左右摇摆"
            },
            {
                "name": "抬腿运动",
                "joint_angles": {
                    "left_leg": 45,
                    "right_leg": -45,
                    "left_arm": 0,
                    "right_arm": 0,
                    "head": 0
                },
                "duration": 1.5,
                "description": "左右腿交替抬起"
            },
            {
                "name": "伸展运动",
                "joint_angles": {
                    "left_arm": -90,
                    "right_arm": -90,
                    "head": 0,
                    "left_leg": 0,
                    "right_leg": 0
                },
                "duration": 2.0,
                "description": "双臂向上伸展"
            }
        ]
        
        # 将预设动作显示在列表中
        preset_text = ""
        for i, action in enumerate(preset_actions):
            preset_text += f"[{i+1}] {action['name']}\n"
            preset_text += f"    描述: {action['description']}\n"
            preset_text += f"    持续时间: {action['duration']}秒\n"
            preset_text += f"    关节角度: {action['joint_angles']}\n\n"
        
        self.preset_list.setPlainText(preset_text.strip())
        self.preset_actions = preset_actions  # 保存预设动作数据
        
        # 保存预设动作库的文件路径
        self.preset_file_path = "preset_actions.json"
        # 保存初始预设动作，用于重置
        self.default_preset_actions = preset_actions.copy()
        
    def preset_list_clicked(self, event):
        """处理预设动作库点击事件"""
        # 如果正在编辑预设动作库，则不执行添加动作到时间轴的操作
        if self.is_preset_editing:
            super().mousePressEvent(event)
            return
            
        cursor = self.preset_list.cursorForPosition(event.pos())
        line_number = cursor.blockNumber()
        
        # 计算点击的是哪个动作（每5行一个动作组）
        action_index = line_number // 5
        
        if 0 <= action_index < len(self.preset_actions):
            try:
                # 获取选中的预设动作
                action = self.preset_actions[action_index]
                
                # 如果使用的是完整的时间轴编辑器，添加动作到时间轴
                if hasattr(self.timeline_editor, 'add_preset_action'):
                    # 使用专门的预设动作添加方法
                    self.timeline_editor.add_preset_action(action)
                    
                    InfoBar.success(
                        title='添加成功',
                        content=f"已将 '{action['name']}' 添加到时间轴",
                        orient=Qt.Horizontal,
                        isClosable=True,
                        position=InfoBarPosition.TOP,
                        duration=2000,
                        parent=self
                    )
                else:
                    # 如果使用的是简单文本编辑器，添加动作到文本
                    action_data = {
                        'name': action['name'],
                        'timestamp': time.time(),
                        'duration': action['duration'],
                        'joint_angles': action['joint_angles']
                    }
                    
                    current_text = self.timeline_editor.toPlainText()
                    if current_text:
                        current_text += "\n"
                    current_text += json.dumps(action_data, indent=2, ensure_ascii=False)
                    self.timeline_editor.setPlainText(current_text)
                    
                    InfoBar.success(
                        title='添加成功',
                        content=f"已将 '{action['name']}' 添加到时间轴",
                        orient=Qt.Horizontal,
                        isClosable=True,
                        position=InfoBarPosition.TOP,
                        duration=2000,
                        parent=self
                    )
                    
            except Exception as e:
                InfoBar.error(
                    title='添加失败',
                    content=f"添加预设动作时发生错误: {str(e)}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        else:
            # 点击的不是有效的动作行
            super().mousePressEvent(event)  # 调用父类方法确保正常处理
            return
            
        super().mousePressEvent(event)  # 调用父类方法确保正常处理
        
    def save_preset_library(self):
        """保存预设动作库到文件"""
        try:
            filename, _ = QFileDialog.getSaveFileName(
                self, "保存预设动作库", self.preset_file_path or "preset_actions.json", 
                "JSON Files (*.json)")
            if filename:
                with open(filename, 'w', encoding='utf-8') as f:
                    json.dump(self.preset_actions, f, indent=2, ensure_ascii=False)
                
                self.preset_file_path = filename
                InfoBar.success(
                    title='保存成功',
                    content=f"预设动作库已保存到 {filename}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='保存失败',
                content=f"保存预设动作库时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
    
    def load_preset_library(self):
        """从文件加载预设动作库"""
        try:
            filename, _ = QFileDialog.getOpenFileName(
                self, "加载预设动作库", "", "JSON Files (*.json)")
            if filename:
                with open(filename, 'r', encoding='utf-8') as f:
                    loaded_actions = json.load(f)
                
                # 验证加载的数据格式
                if not isinstance(loaded_actions, list):
                    raise ValueError("预设动作库文件格式错误")
                    
                for action in loaded_actions:
                    if not all(k in action for k in ['name', 'joint_angles', 'duration', 'description']):
                        raise ValueError(f"动作数据格式错误: {action.get('name', '未知动作')}")
                
                self.preset_actions = loaded_actions
                self.update_preset_list_display()
                self.preset_file_path = filename
                
                InfoBar.success(
                    title='加载成功',
                    content=f"预设动作库已从 {filename} 加载",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='加载失败',
                content=f"加载预设动作库时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
    
    def edit_preset_library(self):
        """编辑预设动作库"""
        try:
            # 设置编辑状态标志
            self.is_preset_editing = True
            
            # 创建编辑对话框
            dialog = PresetActionEditDialog(self.preset_actions.copy(), self)
            if dialog.exec_() == QDialog.Accepted:
                # 更新预设动作库
                self.preset_actions = dialog.get_preset_actions()
                # 刷新显示
                self.refresh_preset_actions_display()
                InfoBar.success(
                    title='更新成功',
                    content="预设动作库已更新",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
            
            # 重置编辑状态标志
            self.is_preset_editing = False
        except Exception as e:
            # 重置编辑状态标志
            self.is_preset_editing = False
            InfoBar.error(
                title='编辑失败',
                content=f"编辑预设动作库时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
    
    def refresh_preset_actions_display(self):
        """刷新预设动作库的显示内容"""
        preset_text = ""
        for i, action in enumerate(self.preset_actions):
            preset_text += f"[{i+1}] {action['name']}\n"
            preset_text += f"    描述: {action['description']}\n"
            preset_text += f"    持续时间: {action['duration']}秒\n"
            preset_text += f"    关节角度: {action['joint_angles']}\n\n"
        
        self.preset_list.setPlainText(preset_text.strip())
    def refresh_serial_ports(self):
        """刷新串口列表"""
        # 清空现有选项
        self.serial_port_combo.clear()
        
        if not SERIAL_AVAILABLE:
            self.serial_port_combo.addItem("串口功能不可用")
            return
            
        try:
            # 获取所有可用的串口
            ports = serial.tools.list_ports.comports()
            for port in ports:
                # 添加串口到下拉列表，显示设备名称和描述
                self.serial_port_combo.addItem(f"{port.device} - {port.description}", port.device)
                
            # 如果没有找到串口，添加提示信息
            if not ports:
                self.serial_port_combo.addItem("未找到可用串口")
                
        except Exception as e:
            print(f"刷新串口列表时出错: {e}")
            self.serial_port_combo.addItem("刷新串口出错")   
        
    def add_custom_action(self):
        """添加自定义动作"""
        try:
            # 如果使用的是完整的时间轴编辑器，调用其添加动作方法
            if hasattr(self.timeline_editor, 'add_action'):
                self.timeline_editor.add_action()
                InfoBar.success(
                    title='添加成功',
                    content="已添加新的自定义动作",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
            else:
                # 如果使用的是简单文本编辑器，添加默认动作文本
                current_text = self.timeline_editor.toPlainText()
                new_action = {
                    'name': f'动作{len(current_text.splitlines()) + 1 if current_text else 1}',
                    'timestamp': len(current_text.splitlines()) * 1.0 if current_text else 0.0,
                    'duration': 1.0,
                    'joint_angles': {
                        'left_arm': 0,
                        'right_arm': 0,
                        'left_leg': 0,
                        'right_leg': 0,
                        'head': 0
                    }
                }
                
                if current_text:
                    current_text += "\n"
                current_text += json.dumps(new_action, indent=2, ensure_ascii=False)
                self.timeline_editor.setPlainText(current_text)
                
                InfoBar.success(
                    title='添加成功',
                    content="已添加新的自定义动作",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='添加失败',
                content=f"添加自定义动作时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            
    def create_ai_interface(self):
        """创建AI对话界面"""
        interface = QWidget()
        layout = QVBoxLayout(interface)
        layout.setSpacing(15)
        
        # AI对话区域
        ai_group = CardWidget()
        ai_layout = QVBoxLayout(ai_group)
        ai_layout.setContentsMargins(20, 20, 20, 20)
        
        # 对话历史显示
        self.ai_chat_history = QTextEdit()
        self.ai_chat_history.setReadOnly(True)
        self.ai_chat_history.setMaximumHeight(300)
        self.ai_chat_history.setPlaceholderText("AI对话历史将在此显示...")
        ai_layout.addWidget(QLabel("对话历史"))
        ai_layout.addWidget(self.ai_chat_history)
        
        # 用户输入区域
        input_layout = QHBoxLayout()
        self.ai_user_input = LineEdit()
        self.ai_user_input.setPlaceholderText("请输入您要与AI对话的内容...")
        self.ai_user_input.returnPressed.connect(self.send_ai_message)
        self.send_ai_btn = PrimaryPushButton("发送")
        self.send_ai_btn.clicked.connect(self.send_ai_message)
        
        # 添加语音识别按钮
        self.speech_btn = PushButton("语音输入")
        # 检查xfyun_speech是否可用
        if SPEECH_RECOGNITION_AVAILABLE:
            self.speech_btn.clicked.connect(self.speech_to_text)
        else:
            self.speech_btn.setEnabled(False)
            self.speech_btn.setToolTip("未找到xfyun_speech模块")
            
        input_layout.addWidget(self.ai_user_input)
        input_layout.addWidget(self.send_ai_btn)
        input_layout.addWidget(self.speech_btn)
        ai_layout.addLayout(input_layout)
        
        # AI设置区域
        settings_group = CardWidget()
        settings_layout = QVBoxLayout(settings_group)
        settings_layout.setContentsMargins(20, 20, 20, 20)
        
        settings_title = QLabel("AI设置")
        settings_title.setFont(QFont("Arial", 12, QFont.Bold))
        settings_layout.addWidget(settings_title)
        
        # 讯飞API配置信息提示
        api_config_info = QLabel("讯飞星火大模型配置信息已内置")
        api_config_info.setStyleSheet("color: gray;")
        settings_layout.addWidget(api_config_info)
        
        # 发送到机器人选项
        send_to_robot_layout = QHBoxLayout()
        send_to_robot_layout.addWidget(QLabel("发送到机器人:"))
        self.send_to_robot_checkbox = ToggleButton()
        self.send_to_robot_checkbox.setChecked(True)
        send_to_robot_layout.addWidget(self.send_to_robot_checkbox)
        settings_layout.addLayout(send_to_robot_layout)
        
        # 添加到主布局
        layout.addWidget(ai_group)
        layout.addWidget(settings_group)
        layout.addStretch(1)
        
        return interface
        
    def send_ai_message(self):
        """发送AI消息"""
        user_message = self.ai_user_input.text().strip()
        if not user_message:
            InfoBar.warning(
                title='输入为空',
                content="请输入要发送给AI的内容",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        # 添加用户消息到聊天历史
        self.ai_chat_history.append(f"用户: {user_message}")
        
        # 清空输入框
        self.ai_user_input.clear()
        
        # 在新线程中处理AI响应，避免阻塞UI
        ai_thread = threading.Thread(target=self.process_ai_response, args=(user_message,))
        ai_thread.daemon = True
        ai_thread.start()
        
    def speech_to_text(self):
        """语音转文本"""
        if not SPEECH_RECOGNITION_AVAILABLE:
            InfoBar.error(
                title='功能不可用',
                content="未找到xfyun_speech模块，请检查模块是否正确安装",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        # 在新线程中处理语音识别，避免阻塞UI
        speech_thread = threading.Thread(target=self.process_speech_recognition)
        speech_thread.daemon = True
        speech_thread.start()
        
    def process_speech_recognition(self):
        """处理语音识别"""
        try:
            # 显示正在识别的提示
            from PyQt5.QtCore import QMetaObject, Qt
            QMetaObject.invokeMethod(
                self, 
                "show_speech_status", 
                Qt.QueuedConnection,
                Q_ARG(str, "正在识别语音，请说话...")
            )
            
            # 从配置中获取讯飞API参数
            from config_manager import get_config_manager
            config = get_config_manager()
            
            app_id = config.get('xfyun.app_id', 'afed0bdd')
            api_key = config.get('xfyun.api_key', '8900a3deaab7ae489182e5503cb535d2')
            api_secret = config.get('xfyun.api_secret', 'ZjEyNTgwMjc4YzdlOGNkMDkyYzI0YThj')
            
            # 调用讯飞语音识别
            text = recognize_speech(app_id, api_key, api_secret)
            
            # 在主线程中更新UI
            from PyQt5.QtCore import QMetaObject, Qt
            QMetaObject.invokeMethod(
                self, 
                "update_speech_result", 
                Qt.QueuedConnection,
                Q_ARG(str, text)
            )
            
        except Exception as e:
            from PyQt5.QtCore import QMetaObject, Qt
            QMetaObject.invokeMethod(
                self, 
                "show_speech_error", 
                Qt.QueuedConnection,
                Q_ARG(str, f"语音识别错误: {str(e)}")
            )
            
    @pyqtSlot(str)
    def show_speech_status(self, message):
        """显示语音识别状态"""
        self.ai_chat_history.append(f"系统: {message}")
        
    @pyqtSlot(str)
    def update_speech_result(self, text):
        """更新语音识别结果"""
        self.ai_chat_history.append(f"识别结果: {text}")
        self.ai_user_input.setText(text)
        
    @pyqtSlot(str)
    def show_speech_error(self, error_message):
        """显示语音识别错误"""
        InfoBar.error(
            title='语音识别错误',
            content=error_message,
            orient=Qt.Horizontal,
            isClosable=True,
            position=InfoBarPosition.TOP,
            duration=2000,
            parent=self
        )
        
    def process_ai_response(self, user_message):
        """处理AI响应"""
        try:
            # 使用讯飞星火大模型
            from X1_http import get_answer, getText, checklen
            
            # 构建对话历史
            chat_history = []
            # 添加用户消息到对话历史
            getText(chat_history, "user", user_message)
            # 检查对话历史长度
            question = checklen(chat_history)
            
            # 调用星火大模型获取回答
            ai_response = get_answer(question)
            
            # 在主线程中更新UI
            from PyQt5.QtCore import QMetaObject, Qt
            QMetaObject.invokeMethod(
                self, 
                "handle_ai_response", 
                Qt.QueuedConnection,
                Q_ARG(str, ai_response)
            )
                
        except Exception as e:
            from PyQt5.QtCore import QMetaObject, Qt
            QMetaObject.invokeMethod(
                self, 
                "show_ai_error", 
                Qt.QueuedConnection,
                Q_ARG(str, f"处理AI响应时发生错误: {str(e)}")
            )
            
    @pyqtSlot(str)
    def handle_ai_response(self, ai_response):
        """处理AI响应并在UI中显示"""
        # 添加AI响应到聊天历史
        self.ai_chat_history.append(f"AI助手: {ai_response}")
        
        # 如果勾选了发送到机器人选项，则发送到机器人
        if self.send_to_robot_checkbox.isChecked():
            # 检查机器人是否已连接
            if self.controller.robot_comm.state.name == "CONNECTED":
                self.controller.robot_comm.send_text_message(ai_response)
                InfoBar.success(
                    title='发送成功',
                    content="AI回复已发送到机器人",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
            else:
                InfoBar.warning(
                    title='发送失败',
                    content="机器人未连接，无法发送AI回复",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
                
    @pyqtSlot(str)
    def show_ai_error(self, error_message):
        """显示AI错误信息"""
        InfoBar.error(
            title='AI错误',
            content=error_message,
            orient=Qt.Horizontal,
            isClosable=True,
            position=InfoBarPosition.TOP,
            duration=2000,
            parent=self
        )
        
    def create_monitor_interface(self):
        """创建实时监控界面"""
        interface = QWidget()
        layout = QVBoxLayout(interface)
        layout.setSpacing(15)
        
        # 系统状态监控
        status_group = CardWidget()
        status_layout = QVBoxLayout(status_group)
        status_layout.setContentsMargins(20, 20, 20, 20)
        
        status_title = QLabel("系统状态")
        status_title.setFont(QFont("Arial", 12, QFont.Bold))
        self.system_status_label = QLabel("系统状态: 就绪")
        self.robot_connection_label = QLabel("机器人连接: 未连接")
        self.audio_status_label = QLabel("音频处理: 空闲")
        
        status_layout.addWidget(status_title)
        status_layout.addWidget(self.system_status_label)
        status_layout.addWidget(self.robot_connection_label)
        status_layout.addWidget(self.audio_status_label)
        
        # 性能监控
        performance_group = CardWidget()
        performance_layout = QVBoxLayout(performance_group)
        performance_layout.setContentsMargins(20, 20, 20, 20)
        
        performance_title = QLabel("性能监控")
        performance_title.setFont(QFont("Arial", 12, QFont.Bold))
        self.cpu_label = QLabel("CPU使用率: --%")
        self.memory_label = QLabel("内存使用: --MB")
        self.network_label = QLabel("网络延迟: --ms")
        
        performance_layout.addWidget(performance_title)
        performance_layout.addWidget(self.cpu_label)
        performance_layout.addWidget(self.memory_label)
        performance_layout.addWidget(self.network_label)
        
        # 实时音频特征显示
        audio_features_group = CardWidget()
        audio_features_layout = QVBoxLayout(audio_features_group)
        audio_features_layout.setContentsMargins(20, 20, 20, 20)
        
        audio_features_title = QLabel("实时音频特征")
        audio_features_title.setFont(QFont("Arial", 12, QFont.Bold))
        self.volume_label = QLabel("音量: --")
        self.frequency_label = QLabel("主频率: --Hz")
        self.beat_label = QLabel("节拍: --")
        self.bpm_label = QLabel("BPM: --")
        
        audio_features_layout.addWidget(audio_features_title)
        audio_features_layout.addWidget(self.volume_label)
        audio_features_layout.addWidget(self.frequency_label)
        audio_features_layout.addWidget(self.beat_label)
        audio_features_layout.addWidget(self.bpm_label)
        
        # 添加到主布局
        layout.addWidget(status_group)
        layout.addWidget(performance_group)
        layout.addWidget(audio_features_group)
        layout.addStretch(1)
        
        return interface
        
    def create_settings_interface(self):
        """创建参数设置界面"""
        interface = QWidget()
        layout = QVBoxLayout(interface)
        layout.setSpacing(15)
        
        # 音频设置
        audio_group = CardWidget()
        audio_layout = QVBoxLayout(audio_group)
        audio_layout.setContentsMargins(20, 20, 20, 20)
        
        audio_title = QLabel("音频设置")
        audio_title.setFont(QFont("Arial", 12, QFont.Bold))
        
        sample_rate_layout = QHBoxLayout()
        sample_rate_layout.addWidget(QLabel("采样率:"))
        self.sample_rate_spin = QSpinBox()
        self.sample_rate_spin.setRange(8000, 192000)
        self.sample_rate_spin.setValue(44100)
        sample_rate_layout.addWidget(self.sample_rate_spin)
        
        sensitivity_layout = QHBoxLayout()
        sensitivity_layout.addWidget(QLabel("节拍敏感度:"))
        self.sensitivity_spin = QDoubleSpinBox()
        self.sensitivity_spin.setRange(0.1, 10.0)
        self.sensitivity_spin.setSingleStep(0.1)
        self.sensitivity_spin.setValue(1.5)
        sensitivity_layout.addWidget(self.sensitivity_spin)
        
        audio_layout.addWidget(audio_title)
        audio_layout.addLayout(sample_rate_layout)
        audio_layout.addLayout(sensitivity_layout)
        
        # 机器人设置
        robot_group = CardWidget()
        robot_layout = QVBoxLayout(robot_group)
        robot_layout.setContentsMargins(20, 20, 20, 20)
        
        robot_title = QLabel("机器人设置")
        robot_title.setFont(QFont("Arial", 12, QFont.Bold))
        
        address_layout = QHBoxLayout()
        address_layout.addWidget(QLabel("机器人地址:"))
        self.robot_address_edit_settings = LineEdit()
        self.robot_address_edit_settings.setText("192.168.1.17")
        address_layout.addWidget(self.robot_address_edit_settings)
        
        port_layout = QHBoxLayout()
        port_layout.addWidget(QLabel("端口:"))
        self.robot_port_spin = QSpinBox()
        self.robot_port_spin.setRange(1, 65535)
        self.robot_port_spin.setValue(8080)
        port_layout.addWidget(self.robot_port_spin)
        
        robot_layout.addWidget(robot_title)
        robot_layout.addLayout(address_layout)
        robot_layout.addLayout(port_layout)
        
        # WiFi配置设置 (用于ESP32串口配置)
        wifi_group = CardWidget()
        wifi_layout = QVBoxLayout(wifi_group)
        wifi_layout.setContentsMargins(20, 20, 20, 20)
        
        wifi_title = QLabel("WiFi配置")
        wifi_title.setFont(QFont("Arial", 12, QFont.Bold))
        
        # WiFi名称
        ssid_layout = QHBoxLayout()
        ssid_layout.addWidget(QLabel("WiFi名称:"))
        self.wifi_ssid_edit = LineEdit()
        self.wifi_ssid_edit.setPlaceholderText("输入WiFi名称")
        ssid_layout.addWidget(self.wifi_ssid_edit)
        
        # WiFi密码
        password_layout = QHBoxLayout()
        password_layout.addWidget(QLabel("WiFi密码:"))
        self.wifi_password_edit = LineEdit()
        self.wifi_password_edit.setPlaceholderText("输入WiFi密码")
        self.wifi_password_edit.setEchoMode(QLineEdit.Password)
        password_layout.addWidget(self.wifi_password_edit)
        
        # 静态IP地址
        static_ip_layout = QHBoxLayout()
        static_ip_layout.addWidget(QLabel("静态IP地址:"))
        self.wifi_static_ip_edit = LineEdit()
        self.wifi_static_ip_edit.setPlaceholderText("可选: 静态IP地址 (如: 192.168.1.100)")
        static_ip_layout.addWidget(self.wifi_static_ip_edit)
        
        # 网关地址
        gateway_layout = QHBoxLayout()
        gateway_layout.addWidget(QLabel("网关地址:"))
        self.wifi_gateway_edit = LineEdit()
        self.wifi_gateway_edit.setPlaceholderText("可选: 网关地址 (如: 192.168.1.1)")
        gateway_layout.addWidget(self.wifi_gateway_edit)
        
        # 子网掩码
        subnet_layout = QHBoxLayout()
        subnet_layout.addWidget(QLabel("子网掩码:"))
        self.wifi_subnet_edit = LineEdit()
        self.wifi_subnet_edit.setText("255.255.255.0")
        subnet_layout.addWidget(self.wifi_subnet_edit)
        
        # 串口名称
        serial_port_layout = QHBoxLayout()
        serial_port_layout.addWidget(QLabel("串口名称:"))
        self.serial_port_combo = ComboBox()
        self.serial_port_combo.setPlaceholderText("选择或输入串口名称")
        # 添加刷新串口按钮
        self.refresh_serial_btn = PushButton("刷新")
        self.refresh_serial_btn.clicked.connect(self.refresh_serial_ports)
        self.refresh_serial_btn.setFixedWidth(60)
        
        serial_port_sub_layout = QHBoxLayout()
        serial_port_sub_layout.addWidget(self.serial_port_combo)
        serial_port_sub_layout.addWidget(self.refresh_serial_btn)
        
        serial_port_layout.addLayout(serial_port_sub_layout)
        
        # 发送WiFi配置按钮
        wifi_btn_layout = QHBoxLayout()
        wifi_btn_layout.addStretch()
        self.send_wifi_config_btn = PrimaryPushButton("发送WiFi配置")
        self.send_wifi_config_btn.clicked.connect(self.send_wifi_config)
        wifi_btn_layout.addWidget(self.send_wifi_config_btn)
        
        wifi_layout.addWidget(wifi_title)
        wifi_layout.addLayout(ssid_layout)
        wifi_layout.addLayout(password_layout)
        wifi_layout.addLayout(static_ip_layout)
        wifi_layout.addLayout(gateway_layout)
        wifi_layout.addLayout(subnet_layout)
        wifi_layout.addLayout(serial_port_layout)
        wifi_layout.addLayout(wifi_btn_layout)
        
        # 界面设置
        ui_group = CardWidget()
        ui_layout = QVBoxLayout(ui_group)
        ui_layout.setContentsMargins(20, 20, 20, 20)
        
        ui_title = QLabel("界面设置")
        ui_title.setFont(QFont("Arial", 12, QFont.Bold))
        
        theme_layout = QHBoxLayout()
        theme_layout.addWidget(QLabel("主题:"))
        self.theme_combo = ComboBox()
        self.theme_combo.addItems(["浅色主题", "深色主题"])
        self.theme_combo.setCurrentIndex(0)  # 默认浅色主题
        theme_layout.addWidget(self.theme_combo)
        
        ui_layout.addWidget(ui_title)
        ui_layout.addLayout(theme_layout)
        
        # 保存按钮
        save_layout = QHBoxLayout()
        save_layout.addStretch()
        self.save_settings_btn = PrimaryPushButton("保存设置")
        self.save_settings_btn.clicked.connect(self.save_settings)
        self.reset_settings_btn = PushButton("重置设置")
        self.reset_settings_btn.clicked.connect(self.reset_settings)
        save_layout.addWidget(self.save_settings_btn)
        save_layout.addWidget(self.reset_settings_btn)
        
        # 添加到主布局
        layout.addWidget(audio_group)
        layout.addWidget(robot_group)
        layout.addWidget(wifi_group)
        layout.addWidget(ui_group)
        layout.addLayout(save_layout)
        layout.addStretch(1)
        
        return interface
        
    def send_wifi_config(self):
        """发送WiFi配置"""
        ssid = self.ssid_edit.text()
        password = self.password_edit.text()
        self.controller.send_wifi_config(ssid, password)
        
    def save_settings(self):
        """保存设置"""
        try:
            # 保存音频设置
            sample_rate = self.sample_rate_spin.value()
            sensitivity = self.sensitivity_spin.value()
            self.controller.config_manager.set('audio.sample_rate', sample_rate)
            self.controller.config_manager.set('audio.beat_sensitivity', sensitivity)
            
            # 保存机器人设置
            robot_address = self.robot_address_edit_settings.text()
            robot_port = self.robot_port_spin.value()
            self.controller.config_manager.set('robot.address', robot_address)
            self.controller.config_manager.set('robot.port', robot_port)
            
            # 保存WiFi配置
            wifi_config = {
                'ssid': self.wifi_ssid_edit.text(),
                'password': self.wifi_password_edit.text(),
                'static_ip': self.wifi_static_ip_edit.text(),
                'gateway': self.wifi_gateway_edit.text(),
                'subnet': self.wifi_subnet_edit.text() or '255.255.255.0'
            }
            self.controller.config_manager.update_section('wifi_config', wifi_config)
            
            # 保存界面设置
            theme_index = self.theme_combo.currentIndex()
            theme = "dark" if theme_index == 1 else "light"
            self.controller.config_manager.set('ui.theme', theme)
            
            # 保存到配置文件
            self.controller.config_manager.save_config()
            
            InfoBar.success(
                title='保存成功',
                content="设置已保存",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
        except Exception as e:
            InfoBar.error(
                title='保存失败',
                content=f"保存设置时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
    
    def reset_settings(self):
        """重置设置"""
        try:
            # 重置音频设置
            self.sample_rate_spin.setValue(44100)
            self.sensitivity_spin.setValue(1.5)
            
            # 重置机器人设置
            self.robot_address_edit_settings.setText("192.168.1.17")
            self.robot_port_spin.setValue(8080)
            
            # 重置WiFi配置
            self.wifi_ssid_edit.clear()
            self.wifi_password_edit.clear()
            self.wifi_static_ip_edit.clear()
            self.wifi_gateway_edit.clear()
            self.wifi_subnet_edit.setText("255.255.255.0")
            
            # 重置界面设置
            self.theme_combo.setCurrentIndex(0)  # 浅色主题
            
            InfoBar.success(
                title='重置成功',
                content="设置已重置为默认值",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
        except Exception as e:
            InfoBar.error(
                title='重置失败',
                content=f"重置设置时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )

        layout.addLayout(save_layout)
        layout.addStretch(1)
        
        return interface
        
    def send_wifi_config(self):
        """发送WiFi配置到ESP32"""
        # 获取WiFi配置信息
        ssid = self.wifi_ssid_edit.text().strip()
        password = self.wifi_password_edit.text().strip()
        static_ip = self.wifi_static_ip_edit.text().strip()
        gateway = self.wifi_gateway_edit.text().strip()
        subnet = self.wifi_subnet_edit.text().strip()
        
        # 从下拉框获取串口名称
        serial_port = None
        current_text = self.serial_port_combo.currentText()
        
        # 检查是否有有效的串口数据
        if self.serial_port_combo.currentIndex() >= 0 and self.serial_port_combo.currentData():
            serial_port = self.serial_port_combo.currentData()
        elif current_text and not current_text.startswith("未找到") and not current_text.startswith("串口功能不可用") and not current_text.startswith("刷新串口出错"):
            # 如果用户手动输入了串口名称，尝试提取实际的COM端口
            import re
            com_match = re.search(r'COM\d+', current_text)
            if com_match:
                serial_port = com_match.group(0)
            else:
                # 回退到使用完整文本
                serial_port = current_text.strip()
        
        # 验证输入
        if not ssid:
            InfoBar.warning(
                title='配置错误',
                content="请输入WiFi名称",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        if not serial_port:
            InfoBar.warning(
                title='配置错误',
                content="请选择或输入串口名称",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
        
        # 构造WiFi配置字典
        wifi_config = {
            'ssid': ssid,
            'password': password,
            'static_ip': static_ip,
            'gateway': gateway,
            'subnet': subnet if subnet else '255.255.255.0'
        }
        
        try:
            # 通过控制器发送WiFi配置
            success = self.controller.send_wifi_config(wifi_config, serial_port)
            
            if success:
                InfoBar.success(
                    title='配置成功',
                    content="WiFi配置已发送到ESP32!\n请重启ESP32以应用新的WiFi配置。",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=3000,
                    parent=self
                )
            else:
                InfoBar.error(
                    title='配置失败',
                    content="无法发送WiFi配置，请检查串口连接。",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
                
        except Exception as e:
            InfoBar.error(
                title='配置错误',
                content=f"发送WiFi配置时出错: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            
    def init_timers(self):
        """初始化定时器"""
        # 状态更新定时器
        self.status_timer = QTimer()
        self.status_timer.timeout.connect(self.update_status)
        self.status_timer.start(1000)  # 每秒更新一次
        
        # 系统监控定时器
        self.monitor_timer = QTimer()
        self.monitor_timer.timeout.connect(self.update_monitor_info)
        self.monitor_timer.start(2000)  # 每2秒更新一次
        
    def initialize_system(self):
        """初始化系统"""
        try:
            success = self.controller.initialize_system()
            if success:
                InfoBar.success(
                    title='系统初始化',
                    content="系统初始化成功",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
            else:
                InfoBar.error(
                    title='系统初始化',
                    content="系统初始化失败，请检查配置",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='初始化错误',
                content=f"初始化过程中发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
        
        
    def play_music(self):
        """播放音乐"""
        # 检查是否选择了音乐文件
        music_file = self.music_file_edit.text().strip()
        if not music_file:
            InfoBar.warning(
                title='播放失败',
                content="请先选择音频文件",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        try:
            # 如果之前已加载音乐且文件相同，则继续播放
            if self.music_loaded and hasattr(self, 'current_music_file') and self.current_music_file == music_file:
                self.pygame.mixer.music.unpause()
            else:
                # 停止当前播放的音乐
                self.pygame.mixer.music.stop()
                # 加载并播放新音乐
                self.pygame.mixer.music.load(music_file)
                self.pygame.mixer.music.play()
                self.music_loaded = True
                self.current_music_file = music_file
                
                # 设置初始音量
                volume = self.volume_slider.value() / 100.0
                self.pygame.mixer.music.set_volume(volume)
                
            # 启动或重启波形更新定时器
            if not hasattr(self, 'waveform_timer'):
                self.waveform_timer = QTimer()
                self.waveform_timer.timeout.connect(self.update_audio_waveform)
            else:
                self.waveform_timer.stop()
                
            self.waveform_timer.start(50)  # 每50毫秒更新一次，使效果更流畅

            # 更新按钮状态
            self.play_btn.setEnabled(False)
            self.pause_btn.setEnabled(True)
            self.stop_btn.setEnabled(True)
            
        except Exception as e:
            InfoBar.error(
                title='播放失败',
                content=f"播放音乐时出错: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=3000,
                parent=self
            )
            
    def update_audio_waveform(self):
        """更新音频波形效果"""
        # 这里应该从音频流中获取实时数据
        # 目前使用空实现
        try:
            pass
        except Exception as e:
            print(f"更新音频波形时出错: {e}")
            
    def pause_music(self):
        """暂停音乐"""
        if self.pygame and self.music_loaded:
            try:
                self.pygame.mixer.music.pause()
                
                # 暂停波形更新定时器
                if hasattr(self, 'waveform_timer'):
                    self.waveform_timer.stop()
                    
                # 更新按钮状态
                self.play_btn.setText("播放")
                self.play_btn.setEnabled(True)
                self.pause_btn.setEnabled(False)
            except Exception as e:
                # 即使发生错误，也要尝试恢复UI状态和停止定时器
                self.play_btn.setText("播放")
                self.play_btn.setEnabled(True)
                self.pause_btn.setEnabled(False)
                if hasattr(self, 'waveform_timer'):
                    self.waveform_timer.stop()
                
                InfoBar.error(
                    title='操作失败',
                    content=f"暂停音乐时出错: {str(e)}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
                
    def stop_music(self):
        """停止音乐"""
        if self.pygame and self.music_loaded:
            try:
                self.pygame.mixer.music.stop()
                self.music_loaded = False
                
                # 停止波形更新定时器
                if hasattr(self, 'waveform_timer'):
                    self.waveform_timer.stop()
                    
                # 清除当前音乐文件记录
                if hasattr(self, 'current_music_file'):
                    delattr(self, 'current_music_file')
                    
                # 重新显示默认波形
                self.update_waveform_display()
                
                # 更新按钮状态
                self.play_btn.setText("播放")
                self.play_btn.setEnabled(True)
                self.pause_btn.setEnabled(False)
                self.stop_btn.setEnabled(False)
            except Exception as e:
                # 即使发生错误，也要尝试恢复UI状态
                self.play_btn.setText("播放")
                self.play_btn.setEnabled(True)
                self.pause_btn.setEnabled(False)
                self.stop_btn.setEnabled(False)
                if hasattr(self, 'waveform_timer'):
                    self.waveform_timer.stop()
                self.update_waveform_display()  # 确保波形被重置
                
                InfoBar.error(
                    title='操作失败',
                    content=f"停止音乐时出错: {str(e)}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
                
    def connect_robot(self):
        """连接机器人"""
        address = self.robot_address_edit.text()
        if not address:
            InfoBar.warning(
                title='连接失败',
                content="请输入机器人地址",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        # 尝试连接机器人
        try:
            self.connection_status_label.setText(f"连接状态: 正在连接 {address}...")
            self.connect_btn.setEnabled(False)
            
            # 实际调用控制器的连接方法
            success = self.controller.robot_comm.connect(address)
            
            if success:
                self.connection_status_label.setText(f"连接状态: 已连接 ({address})")
                self.connect_btn.setEnabled(False)
                self.disconnect_btn.setEnabled(True)
                self.start_dance_btn.setEnabled(True)
                
                InfoBar.success(
                    title='连接成功',
                    content=f"已成功连接到机器人 {address}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
            else:
                self.connection_status_label.setText("连接状态: 连接失败")
                self.connect_btn.setEnabled(True)
                InfoBar.error(
                    title='连接失败',
                    content="无法连接到机器人，请检查地址和网络连接",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            self.connection_status_label.setText("连接状态: 连接失败")
            self.connect_btn.setEnabled(True)
            InfoBar.error(
                title='连接失败',
                content=f"连接机器人时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            
    def disconnect_robot(self):
        """断开机器人连接"""
        try:
            # 调用控制器的断开连接方法
            self.controller.robot_comm.disconnect()
            
            self.connection_status_label.setText("连接状态: 未连接")
            self.connect_btn.setEnabled(True)
            self.disconnect_btn.setEnabled(False)
            self.start_dance_btn.setEnabled(False)
            self.stop_dance_btn.setEnabled(False)
            
            InfoBar.success(
                title='断开连接',
                content="已断开与机器人的连接",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
        except Exception as e:
            InfoBar.error(
                title='断开连接失败',
                content=f"断开连接时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            
    def start_dance(self):
        """开始舞蹈"""
        # 移除系统状态检查，恢复原来的逻辑
        
        # 防止重复点击
        if not self.start_dance_btn.isEnabled():
            print("舞蹈已启动，请勿重复点击")
            return
            
        # 获取当前选择的舞蹈模式
        mode_text = self.mode_combo.currentText()
        mode_data = self.mode_combo.currentData()
        mode_map = {
            "实时跟随": "realtime",
            "预设动作": "preset", 
            "即兴创作": "improvise",
            "编辑模式": "editing"
        }
        mode = mode_map.get(mode_text, mode_data)  # 优先使用data值，如果没有则使用text映射
        
        print(f"启动舞蹈模式: {mode}")
        
        # 如果是编辑模式，需要先设置动作序列
        if mode == "editing":
            try:
                # 从时间轴编辑器获取动作数据
                actions_data = []
                if hasattr(self.timeline_editor, 'get_actions_data'):
                    actions_data = self.timeline_editor.get_actions_data()
                else:
                    # 如果是文本编辑器，尝试解析JSON
                    text = self.timeline_editor.toPlainText()
                    if text.strip():
                        import json
                        actions_data = json.loads(text)
                
                print(f"从时间轴获取动作数据，数量: {len(actions_data)}")
                if actions_data:
                    # 将动作数据设置到动作生成器
                    self.controller.motion_generator.set_editing_sequence(actions_data)
                else:
                    InfoBar.warning(
                        title='警告',
                        content="时间轴中没有动作序列，请先添加动作",
                        orient=Qt.Horizontal,
                        isClosable=True,
                        position=InfoBarPosition.TOP,
                        duration=2000,
                        parent=self
                    )
                    return
            except Exception as e:
                InfoBar.error(
                    title='错误',
                    content=f"无法获取时间轴数据: {str(e)}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
                return
        
        # 启动对应的舞蹈模式
        try:
            success = False
            if mode == "realtime":
                success = self.controller.start_realtime_mode()
                if success:
                    print("实时模式启动成功")
                    # 启动实时监控更新
                    if hasattr(self, 'realtime_monitor_timer'):
                        self.realtime_monitor_timer.stop()
                    else:
                        self.realtime_monitor_timer = QTimer()
                        self.realtime_monitor_timer.timeout.connect(self.update_realtime_monitor)
                    self.realtime_monitor_timer.start(100)  # 每100毫秒更新一次
            elif mode == "preset":
                success = self.controller.start_preset_mode()
            elif mode == "editing":
                success = self.controller.start_editing_mode()
            # TODO: 添加其他模式的处理
            
            if success:
                self.start_dance_btn.setEnabled(False)
                self.stop_dance_btn.setEnabled(True)
                InfoBar.success(
                    title='启动成功',
                    content=f"舞蹈模式 '{mode_text}' 已启动",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
            else:
                InfoBar.warning(
                    title='启动失败',
                    content=f"无法启动舞蹈模式 '{mode_text}'",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='启动错误',
                content=f"启动舞蹈模式时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            
    def stop_dance(self):
        """停止舞蹈"""
        print("停止舞蹈...")
        
        # 停止实时监控更新
        if hasattr(self, 'realtime_monitor_timer') and self.realtime_monitor_timer.isActive():
            self.realtime_monitor_timer.stop()
            
        # 停止舞蹈
        success = self.controller.stop()
        
        if success:
            self.start_dance_btn.setEnabled(True)
            self.stop_dance_btn.setEnabled(False)
            InfoBar.success(
                title='停止成功',
                content="舞蹈已停止",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
        else:
            InfoBar.warning(
                title='停止失败',
                content="停止舞蹈时出现问题",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            
    def update_status(self):
        """更新状态信息"""
        try:
            # 获取系统状态
            status = self.controller.get_system_status()
            
            # 更新系统状态显示
            if hasattr(self, 'system_status_label'):
                self.system_status_label.setText(f"系统状态: {status['state']}")
            
            # 更新机器人连接状态显示
            if hasattr(self, 'robot_connection_label'):
                robot_status = status['robot_status']
                self.robot_connection_label.setText(f"机器人连接: {robot_status['state']}")
            
            # 更新音频处理状态显示
            if hasattr(self, 'audio_status_label'):
                # 根据系统状态判断音频处理状态
                current_state = self.controller.state_manager.get_current_state()
                if current_state == SystemState.PLAYING:
                    if self.controller.motion_generator.mode.name == "REALTIME":
                        self.audio_status_label.setText("音频处理: 实时跟随运行中")
                    else:
                        self.audio_status_label.setText("音频处理: 运行中")
                else:
                    self.audio_status_label.setText("音频处理: 空闲")
                    
        except Exception as e:
            print(f"更新状态信息时出错: {e}")
            
    def update_monitor_info(self):
        """更新监控信息"""
        try:
            # 获取系统状态
            status = self.controller.get_system_status()
            
            # 更新性能监控
            if hasattr(self, 'cpu_progress'):
                # 模拟CPU使用率，实际应用中应该获取真实的系统资源使用情况
                import random
                self.cpu_progress.setValue(random.randint(10, 90))
                
            if hasattr(self, 'memory_progress'):
                # 模拟内存使用率
                self.memory_progress.setValue(random.randint(20, 80))
                
            # 更新系统日志显示
            if hasattr(self, 'log_display'):
                # 显示一些系统状态信息作为日志
                log_text = f"系统状态: {status['state']}\n"
                log_text += f"舞蹈模式: {status['mode']}\n"
                log_text += f"机器人状态: {status['robot_status']['state']}\n"
                log_text += f"音频节拍数: {status['audio_stats']['total_beats']}\n"
                log_text += f"当前BPM: {status['audio_stats']['bpm']:.1f}\n"
                
                self.log_display.setPlainText(log_text)
                
        except Exception as e:
            print(f"更新监控信息时出错: {e}")

    def update_realtime_monitor(self):
        """更新实时监控信息"""
        try:
            # 获取实时音频数据
            audio_data = self.controller.audio_manager.get_current_data()
            
            if audio_data and 'features' in audio_data and audio_data['features']:
                features = audio_data['features']
                
                # 更新日志显示
                if hasattr(self, 'log_display'):
                    log_text = f"实时音频特征:\n"
                    log_text += f"  音量(RMS): {features.get('amplitude_rms', 0):.2f}\n"
                    log_text += f"  主频率: {features.get('dominant_frequency', 0):.0f} Hz\n"
                    log_text += f"  节拍检测: {features.get('is_beat', False)}\n"
                    log_text += f"  BPM: {features.get('bpm', 0):.1f}\n"
                    log_text += f"  总节拍数: {audio_data.get('total_beats', 0)}\n"
                    
                    # 获取生成的动作信息
                    current_state = self.controller.state_manager.get_current_state()
                    if current_state == SystemState.PLAYING:
                        if self.controller.motion_generator.mode.name == "REALTIME":
                            log_text += f"  舞蹈模式: 实时跟随\n"
                        else:
                            log_text += f"  舞蹈模式: {self.controller.motion_generator.mode.name}\n"
                    
                    self.log_display.setPlainText(log_text)
                    
        except Exception as e:
            print(f"更新实时监控信息时出错: {e}")
            
    def closeEvent(self, event):
        """关闭事件处理"""
        reply = QMessageBox.question(
            self, '确认退出', '确定要退出机器人控制系统吗？',
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        
        if reply == QMessageBox.Yes:
            self.controller.cleanup()
            event.accept()
        else:
            event.ignore()

    def save_sequence(self):
        """保存序列"""
        try:
            filename, _ = QFileDialog.getSaveFileName(
                self, "保存序列", "", "JSON Files (*.json)")
            if filename:
                # 如果使用的是完整的时间轴编辑器，获取序列数据
                if hasattr(self.timeline_editor, 'get_sequence_data'):
                    sequence_data = self.timeline_editor.get_sequence_data()
                else:
                    # 如果使用的是简单文本编辑器，获取文本内容
                    sequence_data = self.timeline_editor.toPlainText()
                
                with open(filename, 'w', encoding='utf-8') as f:
                    if isinstance(sequence_data, str):
                        f.write(sequence_data)
                    else:
                        json.dump(sequence_data, f, indent=2, ensure_ascii=False)
                
                InfoBar.success(
                    title='保存成功',
                    content=f"序列已保存到 {filename}",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='保存失败',
                content=f"保存序列时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
    
    def load_sequence(self):
        """加载序列"""
        try:
            filename, _ = QFileDialog.getOpenFileName(
                self, "加载序列", "", "JSON Files (*.json)")
            if filename:
                with open(filename, 'r', encoding='utf-8') as f:
                    sequence_data = json.load(f)
                
                # 如果使用的是完整的时间轴编辑器，设置序列数据
                if hasattr(self.timeline_editor, 'set_sequence_data'):
                    self.timeline_editor.set_sequence_data(sequence_data)
                else:
                    # 如果使用的是简单文本编辑器，设置文本内容
                    self.timeline_editor.setPlainText(json.dumps(sequence_data, indent=2, ensure_ascii=False))
                
                InfoBar.success(
                    title='加载成功',
                    content=f"序列已从 {filename} 加载",
                    orient=Qt.Horizontal,
                    isClosable=True,
                    position=InfoBarPosition.TOP,
                    duration=2000,
                    parent=self
                )
        except Exception as e:
            InfoBar.error(
                title='加载失败',
                content=f"加载序列时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
    
    def clear_sequence(self):
        """清空序列"""
        try:
            # 如果使用的是完整的时间轴编辑器，清空序列数据
            if hasattr(self.timeline_editor, 'clear_sequence'):
                self.timeline_editor.clear_sequence()
            else:
                # 如果使用的是简单文本编辑器，清空文本内容
                self.timeline_editor.clear()
            
            InfoBar.success(
                title='清空成功',
                content="序列已清空",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
        except Exception as e:
            InfoBar.error(
                title='清空失败',
                content=f"清空序列时发生错误: {str(e)}",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )


class PresetActionEditDialog(QDialog):
    """预设动作编辑对话框"""
    def __init__(self, preset_actions=None, parent=None):
        super().__init__(parent)
        self.preset_actions = preset_actions or []
        self.init_ui()
        
    def init_ui(self):
        self.setWindowTitle("预设动作库编辑")
        self.resize(800, 600)
        
        layout = QVBoxLayout()
        
        # 动作列表
        list_layout = QHBoxLayout()
        self.action_list = QListWidget()
        self.action_list.setMaximumWidth(200)
        self.action_list.itemClicked.connect(self.on_action_selected)
        list_layout.addWidget(self.action_list)
        
        # 动作编辑区域
        edit_layout = QVBoxLayout()
        edit_layout.addWidget(QLabel("动作名称:"))
        self.name_edit = QLineEdit()
        edit_layout.addWidget(self.name_edit)
        
        edit_layout.addWidget(QLabel("描述:"))
        self.desc_edit = QLineEdit()
        edit_layout.addWidget(self.desc_edit)
        
        edit_layout.addWidget(QLabel("持续时间 (秒):"))
        self.duration_edit = QDoubleSpinBox()
        self.duration_edit.setRange(0.1, 10.0)
        self.duration_edit.setSingleStep(0.1)
        edit_layout.addWidget(self.duration_edit)
        
        edit_layout.addWidget(QLabel("关节角度 (JSON格式):"))
        self.joints_edit = QTextEdit()
        self.joints_edit.setMaximumHeight(150)
        edit_layout.addWidget(self.joints_edit)
        
        # 按钮
        button_layout = QHBoxLayout()
        self.add_btn = PrimaryPushButton("添加动作")
        self.update_btn = PrimaryPushButton("更新动作")
        self.delete_btn = PushButton("删除动作")
        self.add_btn.clicked.connect(self.add_action)
        self.update_btn.clicked.connect(self.update_action)
        self.delete_btn.clicked.connect(self.delete_action)
        button_layout.addWidget(self.add_btn)
        button_layout.addWidget(self.update_btn)
        button_layout.addWidget(self.delete_btn)
        
        edit_layout.addLayout(button_layout)
        list_layout.addLayout(edit_layout)
        
        layout.addLayout(list_layout)
        
        # 对话框按钮
        dialog_buttons = QHBoxLayout()
        self.ok_btn = PrimaryPushButton("确定")
        self.cancel_btn = PushButton("取消")
        self.ok_btn.clicked.connect(self.accept)
        self.cancel_btn.clicked.connect(self.reject)
        dialog_buttons.addWidget(self.ok_btn)
        dialog_buttons.addWidget(self.cancel_btn)
        layout.addLayout(dialog_buttons)
        
        self.setLayout(layout)
        
        # 初始化动作列表
        self.refresh_action_list()
        
    def refresh_action_list(self):
        """刷新动作列表"""
        self.action_list.clear()
        for i, action in enumerate(self.preset_actions):
            item = QListWidgetItem(f"[{i+1}] {action['name']}")
            self.action_list.addItem(item)
            
    def on_action_selected(self, item):
        """当选中动作时，填充编辑区域"""
        index = self.action_list.row(item)
        if 0 <= index < len(self.preset_actions):
            action = self.preset_actions[index]
            self.name_edit.setText(action['name'])
            self.desc_edit.setText(action['description'])
            self.duration_edit.setValue(action['duration'])
            self.joints_edit.setPlainText(json.dumps(action['joint_angles'], indent=2, ensure_ascii=False))
            
    def add_action(self):
        """添加新动作"""
        name = self.name_edit.text().strip()
        if not name:
            InfoBar.warning(
                title='警告',
                content="动作名称不能为空",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        try:
            joint_angles = json.loads(self.joints_edit.toPlainText())
        except json.JSONDecodeError:
            InfoBar.warning(
                title='警告',
                content="关节角度不是有效的JSON格式",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        action = {
            'name': name,
            'description': self.desc_edit.text(),
            'duration': self.duration_edit.value(),
            'joint_angles': joint_angles
        }
        
        self.preset_actions.append(action)
        self.refresh_action_list()
        
    def update_action(self):
        """更新选中动作"""
        current_row = self.action_list.currentRow()
        if current_row < 0:
            InfoBar.warning(
                title='警告',
                content="请先选择一个动作",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        name = self.name_edit.text().strip()
        if not name:
            InfoBar.warning(
                title='警告',
                content="动作名称不能为空",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        try:
            joint_angles = json.loads(self.joints_edit.toPlainText())
        except json.JSONDecodeError:
            InfoBar.warning(
                title='警告',
                content="关节角度不是有效的JSON格式",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        action = {
            'name': name,
            'description': self.desc_edit.text(),
            'duration': self.duration_edit.value(),
            'joint_angles': joint_angles
        }
        
        self.preset_actions[current_row] = action
        self.refresh_action_list()
        
    def delete_action(self):
        """删除选中动作"""
        current_row = self.action_list.currentRow()
        if current_row < 0:
            InfoBar.warning(
                title='警告',
                content="请先选择一个动作",
                orient=Qt.Horizontal,
                isClosable=True,
                position=InfoBarPosition.TOP,
                duration=2000,
                parent=self
            )
            return
            
        reply = QMessageBox.question(self, "确认", "确定要删除这个动作吗？", 
                                   QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            del self.preset_actions[current_row]
            self.refresh_action_list()
            
    def get_preset_actions(self):
        """获取预设动作列表"""
        return self.preset_actions


def run_fluent_ui():
    """运行QFluentWidgets界面"""
    app = QApplication(sys.argv)
    # 设置浅色主题
    setTheme(Theme.LIGHT)
    
    # 创建并显示主界面
    ui = FluentMainUI()
    ui.show()
    
    sys.exit(app.exec_())


if __name__ == '__main__':
    run_fluent_ui()